In [1]:
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
In [3]:
wineDf = pd.read_csv('wineQuality-red.csv')
wineDf
Out[3]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5
1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8 5
2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8 5
3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8 6
4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5
... ... ... ... ... ... ... ... ... ... ... ... ...
1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5 5
1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2 6
1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0 6
1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2 5
1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6

1599 rows × 12 columns

In [165]:
wineDf.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1599 entries, 0 to 1598
Data columns (total 14 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   fixed acidity         1599 non-null   float64
 1   volatile acidity      1599 non-null   float64
 2   citric acid           1599 non-null   float64
 3   residual sugar        1599 non-null   float64
 4   chlorides             1599 non-null   float64
 5   free sulfur dioxide   1599 non-null   float64
 6   total sulfur dioxide  1599 non-null   float64
 7   density               1599 non-null   float64
 8   pH                    1599 non-null   float64
 9   sulphates             1599 non-null   float64
 10  alcohol               1599 non-null   float64
 11  quality               1599 non-null   int64  
 12  quality Evaluate      1599 non-null   object 
 13  Clusters              1599 non-null   int32  
dtypes: float64(11), int32(1), int64(1), object(1)
memory usage: 168.8+ KB

Fixed.acidity

Normalmente se faz referencia ao ácido tartarico, uns dos principais ácidos encontrados em uvas e um dos principais ácidos do vinho.

Volatile.acidity

A acidez volátil refere-se aos ácidos destilados a vapor presentes no vinho, em grandes quantidades pode levar à um gosto desagradável. O nível médio de ácido acético em um vinho é inferior a 400 mg/L,embora os níveis possam variar de indetectáveis até 3 g/L.

Citric.acid

Presente nas uvas em baixa quantidade, nos vinhos o ácido cítrico tem pouca ou nenhuma presença. Nos vinhos tintos desaparece devido à ação de bactérias láticas (fermentação malolática). Sensorialmente é fresco, porém em alguns casos pode apresentar um leve final amargo.

Residual.sugar

A fermentação de um vinho é feita através do contato do açucar com a levedura, após a fermentação resta o açucar residual. Quando contém até 4 gramas de açucar residual por litro, um vinho pode ser considerado seco, a partir de 25 a 80 gramas é considerado doce ou suave.

Chlorides

Representa a quantidade de sal contidas nos vinhos.

Free.sulfur.dioxide

É uma forma livre de SO2, um gás dissolvido que impede o crescimento de microbios e a oxidação do vinho. Quantidades excessivas de SO2 podem inibir a fermentação e causar efeitos sensoriais indesejáveis.

Total.sulfur.dioxide

O dióxido de enxofre total (TSO2) é a porção de dioxido de enxofre livre (SO2) que está livre no vinho mais a porção que está ligada a outros produtos químicos no vinho.

Density

A densidade do vinho se refere ao corpo do vinho, à sensação de maior ou menor densidade que a bebida apresenta. A densidade do vinho pode variar de acordo com a densidade da água e o teor percentual de álcool e açúcar.

PH

O pH (potencial Hidrogeniônico) é calculado a partir da concentração de íons de hidrogênio. Indica acidez, neutralidade ou alcalinidade de um produto. A escala varia de 0 a 14 e, quanto menor for o índice de pH, maior é a acidez. Abaixo de 7, o pH é ácido, igual a 7 é neutro, e maior que 7 é alcalino.

Nos vinhos em geral, o pH varia de 2,8 (acidez forte) até 3,8 (acidez leve). Com pH acima de 3,5 o vinho é frágil e pode estar sujeito a alterações (defeitos). Um pH baixo tem grande importância na estabilidade do vinho.

Sulphates

O termo sulfato é um termo inclusivo para o dióxido de enxofre (SO2), um conservante que é amplamente utilizado na produção de vinho (e na maioria das indústrias alimentícias) por suas propriedades antioxidantes e antibacterianas. O SO2 desempenha um papel importante na prevenção da oxidação e na manutenção da frescura de um vinho.

Alcohol

Esta variável se refere a porcentagem de alcool contida nos vinhos.

O álcool é a alma do vinho. É a sua maior ou menor presença que define muitas das vezes a sua qualidade. É habitual dizer-se de um vinho com mais de 13% de álcool que é encorpado, vinoso, capitoso, quente. Já um vinho seco com menos de 11% de álcool é um vinho leve, magro, ligeiro e quase sempre desinteressante. Mas álcool em excesso pode tornar um vinho pesado, chato, mole, desinteressante.

A partir do histograma de residual sugar é possivel perceber que tem uma grande distribuição entre 2 à 4, o que posso supor que grande parte dos vinhos analisados são vinhos mais doces.

O teor alcoolico dos vinhos abaixo de 13% pode indicar vinhos mais leves, maior refrescancia. E o Ph está na média de 3,3. Podendo indicar que os vinhos bem avaliados sejam mais secos e om maior acidez.

In [4]:
wineDf.describe()
Out[4]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
count 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000
mean 8.319637 0.527821 0.270976 2.538806 0.087467 15.874922 46.467792 0.996747 3.311113 0.658149 10.422983 5.636023
std 1.741096 0.179060 0.194801 1.409928 0.047065 10.460157 32.895324 0.001887 0.154386 0.169507 1.065668 0.807569
min 4.600000 0.120000 0.000000 0.900000 0.012000 1.000000 6.000000 0.990070 2.740000 0.330000 8.400000 3.000000
25% 7.100000 0.390000 0.090000 1.900000 0.070000 7.000000 22.000000 0.995600 3.210000 0.550000 9.500000 5.000000
50% 7.900000 0.520000 0.260000 2.200000 0.079000 14.000000 38.000000 0.996750 3.310000 0.620000 10.200000 6.000000
75% 9.200000 0.640000 0.420000 2.600000 0.090000 21.000000 62.000000 0.997835 3.400000 0.730000 11.100000 6.000000
max 15.900000 1.580000 1.000000 15.500000 0.611000 72.000000 289.000000 1.003690 4.010000 2.000000 14.900000 8.000000
In [5]:
wineDf['quality'].unique()
Out[5]:
array([5, 6, 7, 4, 8, 3], dtype=int64)
In [6]:
#Função para avaliar agrupar a qualidade em grupos

def evaluateQuality(quality):
    if quality <= 4:
        return 'bad'
    elif quality >=5 and quality <=6:
        return 'moderate'
    else: return 'good'
In [7]:
wineDf['quality Evaluate'] = wineDf['quality'].apply(evaluateQuality)
In [8]:
plt.figure(figsize=(12,6))
sns.set_style('whitegrid')
sns.countplot(x='quality Evaluate',data=wineDf)
Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x1f4c6627fa0>

A primeira coisa a se perceber no plot acima é que a maioria dos vinhos são de qualidade média. Os valores outliers são bem aproximados a vinhos de qualidades ruins e boas, será que os vinhos usados nas avaliações dos especialistas são de uma região especifica? De várias regiões?

In [168]:
plt.figure(figsize=(20,6))
plt.title('Distribuição Alcohol', family='Arial', fontsize=15)
wineDf[(wineDf['alcohol']>7) & (wineDf['alcohol']<14)]['alcohol'].hist()
Out[168]:
<matplotlib.axes._subplots.AxesSubplot at 0x1f4d5ec67c0>
In [10]:
sns.pairplot(wineDf)
Out[10]:
<seaborn.axisgrid.PairGrid at 0x1f4cbc63fa0>
In [163]:
plt.figure(figsize=(15,10))
sns.heatmap(wineDf.corr(),annot=True)
Out[163]:
<matplotlib.axes._subplots.AxesSubplot at 0x1f4dc97ab80>

Os valores que tem maior correlação com a qualidade são alcohol e volatile acidity.

Ph tem uma forte correlação negativa com os ácidos (quanto menor o ph maior acidez), porém com volatile acidity há correlação positiva.

Sulphates e Chlorides tem correlação média, porém somente sulphates tem correlação com a qualidade.

Density tem forte correlação com os ácidos fixed acidity e citric acid, residual sugar e uma forte correlação negativa com alcohol.

é possivel perceber que a qualidade dos vinhos tem um relacionamento forte com a qualidade Fixed acidity tem o maior relacionento com densidade.

In [12]:
wineDf.corr()[['quality','alcohol']]*100
Out[12]:
quality alcohol
fixed acidity 12.405165 -6.166827
volatile acidity -39.055778 -20.228803
citric acid 22.637251 10.990325
residual sugar 1.373164 4.207544
chlorides -12.890656 -22.114054
free sulfur dioxide -5.065606 -6.940835
total sulfur dioxide -18.510029 -20.565394
density -17.491923 -49.617977
pH -5.773139 20.563251
sulphates 25.139708 9.359475
alcohol 47.616632 100.000000
quality 100.000000 47.616632
In [17]:
plt.figure(figsize=(12,8))
_ = plt.plot(wineDf['fixed acidity'],wineDf['density'], marker='.', linewidth=0, color='orange')
_ = plt.grid(which='major', color='#cccccc', alpha=0.45)
_ = plt.title('Red Wines - fixed.acidity vs density', family='Arial', fontsize=12)
_ = plt.xlabel('fixed.acidity')
_ = plt.ylabel('density')
_ = plt.show()


plt.figure(figsize=(12,8))
_ = plt.plot(wineDf['alcohol'],wineDf['pH'], marker='.', linewidth=0, color='blue')
_ = plt.grid(which='major', color='#cccccc', alpha=0.45)
_ = plt.title('Red Wines - Alcohol vs pH', family='Arial', fontsize=12)
_ = plt.xlabel('Alcohol')
_ = plt.ylabel('pH')
_ = plt.show()
In [55]:
wineDf
Out[55]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality quality Evaluate
0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 moderate
1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8 5 moderate
2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8 5 moderate
3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8 6 moderate
4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 moderate
... ... ... ... ... ... ... ... ... ... ... ... ... ...
1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5 5 moderate
1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2 6 moderate
1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0 6 moderate
1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2 5 moderate
1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6 moderate

1599 rows × 13 columns

In [17]:
wineDf.iloc[:,0:11]
Out[17]:
fixed.acidity volatile.acidity citric.acid residual.sugar chlorides free.sulfur.dioxide total.sulfur.dioxide density pH sulphates alcohol
0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4
1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8
2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8
3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8
4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4
... ... ... ... ... ... ... ... ... ... ... ...
1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5
1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2
1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0
1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2
1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0

1599 rows × 11 columns

In [18]:
#CALCULOS ELBOW

def calculate_wcss(data,range1=2,range2=21):
    from sklearn.cluster import KMeans
    wcss = []
    for n in range(2, 21):
        kmeans = KMeans(n_clusters=n, init='k-means++',max_iter=300, n_init=10, random_state=42)
        kmeans.fit(X=data)
        wcss.append(kmeans.inertia_)

    return wcss


def optimal_number_of_clusters(wcss):
    """   
    Parametros
    ----------
    wcss : lista
        lista contendo os valores de soma de quadrados intra-cluster
    Returns
    -------
    int : número de clusters 
    """
    from math import sqrt
    x1, y1 = 2, wcss[0]
    x2, y2 = 21, wcss[len(wcss)-1]

    distances = []
    for i in range(len(wcss)):
        x0 = i+2
        y0 = wcss[i]

        numerator = abs((y2-y1)*x0 - (x2-x1)*y0 + x2*y1 - y2*x1)
        denominator = sqrt((y2 - y1)**2 + (x2 - x1)**2)
        distances.append(numerator/denominator)
    return distances.index(max(distances)) + 2

#PLOT ELBOW
def elbowPlot(range1,range2,n_cluster, w, title='Método Elbow'):
    #plt.figure(figsize=(12,6))
    plt.figure(figsize=(15,10))
    plt.plot(range(range1,range2), w, linewidth = 2, marker='D',markersize=5)
    plt.title(title, fontsize=14)
    plt.xlabel('Numero de Clusters', fontsize=12)
    plt.ylabel('WCSS (inertia)',  fontsize=12)
    plt.grid(which='both',color='black', axis='x', alpha=0.5)

    plt.axvline(x=n_cluster,linewidth=2,color='red',linestyle='--')
In [29]:
sumSquares = calculate_wcss(wineDf.iloc[:,0:12])
#sum_of_squares = wcss
n = optimal_number_of_clusters(sumSquares)

print('N° Clusters = {}'.format(n))
elbowPlot(2,21,n,sumSquares,title='Método Elbow - Red Wines')
N° Clusters = 6

Elbow para Wines

A ideia do Elbow é rodar o KMeans para vários quantidades diferentes de clusters e dizer qual dessas quantidades é o número ótimo de clusters.

O que geralmente acontece ao aumentar a quantidade de clusters no KMeans é que as diferenças entre clusters se tornam muito pequenas, e as diferenças das observações intra-clusters vão aumentando.

-Calcular a função de custo, a soma dos quadrados das distâncias internas dos clusters, e traçá-la em um gráfico.

In [19]:
wines = wineDf.iloc[:,0:12] 
In [20]:
from pylab import rcParams
from sklearn.cluster import KMeans
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler

%matplotlib inline
rcParams['figure.figsize'] = 14,8
sns.set_style('whitegrid')

Normalização Standard Scaler

In [21]:
X_data = wines.values.astype('float32', copy=False)
scaler = StandardScaler().fit(X_data)

winesScaler = scaler.transform(X_data)
In [56]:
winesScaler
Out[56]:
array([[-0.5283596 ,  0.96187663, -1.3914723 , ..., -0.57920647,
        -0.9602464 , -0.78782266],
       [-0.29854733,  1.9674425 , -1.3914723 , ...,  0.12895045,
        -0.58477694, -0.78782266],
       [-0.29854733,  1.2970653 , -1.1860704 , ..., -0.04808896,
        -0.58477694, -0.78782266],
       ...,
       [-1.160343  , -0.09955393, -0.7239163 , ...,  0.54204196,
         0.5416299 ,  0.45084837],
       [-1.3901552 ,  0.65462035, -0.77526677, ...,  0.3059895 ,
        -0.20930828, -0.78782266],
       [-1.3327023 , -1.2168492 ,  1.0219995 , ...,  0.01092441,
         0.5416299 ,  0.45084837]], dtype=float32)
In [26]:
sumSquares_winesScaler = calculate_wcss(winesScaler)
#sum_of_squares = wcss
n_sumSquares_winesScaler = optimal_number_of_clusters(sumSquares_winesScaler)

print('N° Clusters = {}'.format(n_sumSquares_winesScaler))
elbowPlot(2,21,n_sumSquares_winesScaler,sumSquares_winesScaler ,title='Método Elbow - Wines Standard Scaler')
N° Clusters = 7

Normalização Min Max Scaler

In [23]:
#X_data = X_Outlet.values.astype('float32', copy=False)
mms = MinMaxScaler().fit(X_data)

winesMmsScaler = scaler.transform(X_data)
In [25]:
sumSquares_winesMMSScaler = calculate_wcss(winesMmsScaler)
#sum_of_squares = wcss
n_winesMssScaler = optimal_number_of_clusters(sumSquares_winesMMSScaler)

print('N° Clusters = {}'.format(n_winesMssScaler))
elbowPlot(2,21,n_winesMssScaler,sumSquares_winesMMSScaler ,title='Método Elbow - Wines MinMax Scaler')
N° Clusters = 7
In [27]:
kmeans = KMeans(n_clusters=7)
clustersWines = kmeans.fit_predict(winesMmsScaler)
labelsWines = kmeans.labels_

x1, x2 = 2, 20
intervalo = range(x1,x2+1)
In [28]:
def plot_clustering(data, labels, title=None):
    x_min, x_max = np.min(data, axis=0), np.max(data, axis=0)
    data = (data - x_min) / (x_max - x_min)
    fig = plt.figure(1, figsize=(4, 3))
    plt.figure(figsize=(6, 4))
    plt.scatter(data[:, 0], data[:, 1],
                 c=labels.astype(np.float))
    plt.xticks([])
    plt.yticks([])
    if title is not None:
        plt.title(title, size=17)
    plt.axis('off')
    plt.tight_layout(rect=[0, 0.03, 1, 0.95]) 
In [32]:
plot_clustering(winesMmsScaler, labelsWines)
plt.figure(figsize=(14,10))
plt.show()
<Figure size 288x216 with 0 Axes>
<Figure size 1008x720 with 0 Axes>

KMEANS

In [59]:
kmeans.labels_
Out[59]:
array([2, 2, 2, ..., 0, 0, 6])
In [61]:
kmeans.cluster_centers_
Out[61]:
array([[-1.0771065 ,  0.39409992, -0.9230558 , -0.23899068, -0.41415113,
         0.24660656, -0.18688872, -1.3105539 ,  1.1540004 , -0.13473733,
         1.1632905 ,  0.4629329 ],
       [ 1.6498402 , -0.5740718 ,  1.2396276 ,  0.11661626,  0.06548438,
        -0.49958763, -0.4463462 ,  1.1418784 , -0.98218995,  0.24369806,
        -0.05484931,  0.13134988],
       [-0.4200872 ,  0.6486885 , -0.7745256 , -0.21192278, -0.03686635,
        -0.48817787, -0.40371066,  0.01938737,  0.325034  , -0.4122665 ,
        -0.5281018 , -0.506887  ],
       [-0.12260811,  0.02535443,  0.05792119, -0.02205794, -0.03987278,
         0.99622023,  1.2281214 ,  0.2055872 , -0.09834558, -0.1731195 ,
        -0.5710359 , -0.4202643 ],
       [ 0.08183135,  0.01795475,  1.144178  , -0.39939594,  5.604731  ,
        -0.07047901,  0.4744156 ,  0.18580441, -1.6873566 ,  3.7206085 ,
        -0.8825628 , -0.36069468],
       [-0.08563323, -0.03465217,  0.41485575,  4.9617677 ,  0.29638785,
         1.7501911 ,  1.6958323 ,  1.2250003 , -0.32545942, -0.02378932,
        -0.36391294, -0.02276116],
       [ 0.19706896, -1.0063237 ,  0.72248834, -0.10620915, -0.28365043,
        -0.3154903 , -0.5396967 , -0.56347847, -0.20839804,  0.45685187,
         1.0190016 ,  1.0533154 ]], dtype=float32)
In [63]:
wineDf['Clusters'] = kmeans.labels_
wineDf
Out[63]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality quality Evaluate Clusters
0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 moderate 2
1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8 5 moderate 2
2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8 5 moderate 2
3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8 6 moderate 1
4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 moderate 2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5 5 moderate 0
1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2 6 moderate 0
1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0 6 moderate 0
1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2 5 moderate 0
1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6 moderate 6

1599 rows × 14 columns

In [66]:
wineDf['Clusters'].value_counts()
Out[66]:
2    485
3    337
6    257
1    252
0    205
5     34
4     29
Name: Clusters, dtype: int64
In [86]:
wineDf[wineDf['Clusters']==6]
Out[86]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality quality Evaluate Clusters
37 8.1 0.38 0.28 2.1 0.066 13.0 30.0 0.99680 3.23 0.73 9.7 7 good 6
84 6.3 0.30 0.48 1.8 0.069 18.0 61.0 0.99590 3.44 0.78 10.3 6 moderate 6
128 8.0 0.59 0.16 1.8 0.065 3.0 16.0 0.99620 3.42 0.92 10.5 7 good 6
149 8.2 0.40 0.44 2.8 0.089 11.0 43.0 0.99750 3.53 0.61 10.5 6 moderate 6
150 7.3 0.33 0.47 2.1 0.077 5.0 11.0 0.99580 3.33 0.53 10.3 6 moderate 6
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1580 7.4 0.35 0.33 2.4 0.068 9.0 26.0 0.99470 3.36 0.60 11.9 6 moderate 6
1584 6.7 0.32 0.44 2.4 0.061 24.0 34.0 0.99484 3.29 0.80 11.6 7 good 6
1585 7.2 0.39 0.44 2.6 0.066 22.0 48.0 0.99494 3.30 0.84 11.5 6 moderate 6
1586 7.5 0.31 0.41 2.4 0.065 34.0 60.0 0.99492 3.34 0.85 11.4 6 moderate 6
1598 6.0 0.31 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6 moderate 6

257 rows × 14 columns

In [90]:
pd.crosstab(wineDf.quality,kmeans.labels_)
Out[90]:
col_0 0 1 2 3 4 5 6
quality
3 0 2 7 1 0 0 0
4 4 4 38 4 1 1 1
5 33 88 284 232 18 16 10
6 129 122 150 94 9 12 122
7 35 35 6 6 1 5 111
8 4 1 0 0 0 0 13
In [72]:
sns.scatterplot(x='pH',y='density', hue='Clusters', data=wineDf)
Out[72]:
<matplotlib.axes._subplots.AxesSubplot at 0x1f4da727520>
In [74]:
from scipy.cluster.hierarchy import dendrogram
from sklearn.cluster import AgglomerativeClustering


def plot_dendrogram(model, **kwargs):
    # Create linkage matrix and then plot the dendrogram

    # create the counts of samples under each node
    counts = np.zeros(model.children_.shape[0])
    n_samples = len(model.labels_)
    for i, merge in enumerate(model.children_):
        current_count = 0
        for child_idx in merge:
            if child_idx < n_samples:
                current_count += 1  # leaf node
            else:
                current_count += counts[child_idx - n_samples]
        counts[i] = current_count

    linkage_matrix = np.column_stack([model.children_, model.distances_,
                                      counts]).astype(float)

    # Plot the corresponding dendrogram
    dendrogram(linkage_matrix, **kwargs)

setting distance_threshold=0 ensures we compute the full tree.

model = AgglomerativeClustering(distance_threshold=6, n_clusters=6)

model = model.fit(wines) plt.title('Hierarchical Clustering Dendrogram')

plot the top three levels of the dendrogram

plot_dendrogram(model, truncate_mode='level', p=3) plt.xlabel("Number of points in node (or index of point if no parenthesis).") plt.show()

In [81]:
from scipy.cluster.hierarchy import dendrogram, linkage
from matplotlib import pyplot as plt

linked = linkage(wines, 'single')

labelList = range(1, 11)

plt.figure(figsize=(10, 7))
dendrogram(linked,
            orientation='top',
            labels=labelList,
            distance_sort='descending',
            show_leaf_counts=True)
plt.show()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-81-b9085e8a7e39> in <module>
      7 
      8 plt.figure(figsize=(10, 7))
----> 9 dendrogram(linked,
     10             orientation='top',
     11             labels=labelList,

E:\Programs files\anaconda3\lib\site-packages\scipy\cluster\hierarchy.py in dendrogram(Z, p, truncate_mode, color_threshold, get_leaves, orientation, labels, count_sort, distance_sort, show_leaf_counts, no_plot, no_labels, leaf_font_size, leaf_rotation, leaf_label_func, show_contracted, link_color_func, ax, above_threshold_color)
   3276 
   3277     if labels and Z.shape[0] + 1 != len(labels):
-> 3278         raise ValueError("Dimensions of Z and labels must be consistent.")
   3279 
   3280     is_valid_linkage(Z, throw=True, name='Z')

ValueError: Dimensions of Z and labels must be consistent.
<Figure size 720x504 with 0 Axes>
In [162]:
sns.boxplot( y=wines["density"], x=wines["pH"])
plt.show()

Teste Silhouette

A análise por Silhouette mede o quão bem um ponto se encaixa em um cluster. Neste método um gráfico é feito medindo quão perto os pontos de um cluster estão dos pontos de outro cluster mais próximo.

O coeficiente de Silhouette quando próximo de +1, indica que os pontos estão muito longe dos pontos do outro cluster, e quando próximo de 0, indica que os pontos então muito perto ou até interseccionando um outro cluster.

In [35]:
from sklearn.metrics import silhouette_samples, silhouette_score
import numpy as np
In [130]:
silhouette_score(winesMmsScaler, labelsWines)
Out[130]:
0.17652

Teste kmeans para 20 clusters calculando o silhoute

In [131]:
kmeans_per_k = [KMeans(n_clusters=k, random_state=5).fit(winesMmsScaler) for k in range(2,21)]
In [144]:
silhouete_scores = [silhouette_score(winesMmsScaler, model.labels_) for model in kmeans_per_k[1:]]
In [146]:
silhouete_scores
Out[146]:
[0.17351092,
 0.18940628,
 0.18083842,
 0.1688855,
 0.17727827,
 0.13961072,
 0.14443254,
 0.14733526,
 0.12704864,
 0.12803215,
 0.12690397,
 0.12491738,
 0.13143416,
 0.1191554,
 0.12881859,
 0.13104393,
 0.12975244,
 0.12886104]
In [157]:
float(np.argmax(silhouete_scores))
Out[157]:
1.0
In [156]:
#plt.figure(figsize=(16,5))
plt.plot(range(2,20), silhouete_scores,'bo-', color='blue', linewidth = 3, markersize=8, label='Curva Silhouta')
plt.xlabel('$k$', fontsize='14')
plt.ylabel('Silhoute Score', fontsize='14')
plt.grid(which='major', color='#cccccc', linestyle='--')
plt.title('Número de ótimo de clusters preditos pela curva Silhoute', fontsize=14)
         
#Calcula o numero otimo de clusters
k = np.argmax(silhouete_scores)
plt.axvline(x=k, linestyle='--', c='green', linewidth=3, label='Número ótimo de clusters ({})'.format(k))
plt.scatter(k, silhouete_scores[k-2],c='red',s=400)
plt.legend(shadow=True)         
Out[156]:
<matplotlib.legend.Legend at 0x1f4dce0b910>

Este caso o silhoute não perfomou bem, porem iremos rodar o kmeans para varias quantidades de cluster novamente e ver a distribuição dos dados.

Teste kmeans para 10 clusters calculando o silhoute

In [62]:
range_n_clusters = [2, 3, 4, 5, 6,7,8,9,10]
import matplotlib.cm as cm
for n_clusters in range_n_clusters:
    # Create a subplot with 1 row and 2 columns
    fig, (ax1, ax2) = plt.subplots(1, 2)
    fig.set_size_inches(18, 7)
    # The 1st subplot is the silhouette plot
    # The silhouette coefficient can range from -1, 1 but in this example all
    # lie within [-0.1, 1]
    ax1.set_xlim([-0.1, 1])
    # The (n_clusters+1)*10 is for inserting blank space between silhouette
    # plots of individual clusters, to demarcate them clearly.
    ax1.set_ylim([0, len(wines) + (n_clusters + 1) * 10])
    # Initialize the clusterer with n_clusters value and a random generator
    # seed of 10 for reproducibility.
    clusterer = KMeans(n_clusters=n_clusters, random_state=10)
    cluster_labels = clusterer.fit_predict(winesMmsScaler)
# The silhouette_score gives the average value for all the samples.
    # This gives a perspective into the density and separation of the formed
    # clusters
    silhouette_avg = silhouette_score(winesMmsScaler, cluster_labels)
    print("Para n_clusters =", n_clusters,
          "O score_silhouette médio é :", silhouette_avg)
    # Compute the silhouette scores for each sample
    sample_silhouette_values = silhouette_samples(winesMmsScaler, cluster_labels)
    y_lower = 10
    for i in range(n_clusters):
        # Aggregate the silhouette scores for samples belonging to
        # cluster i, and sort them
        ith_cluster_silhouette_values = \
            sample_silhouette_values[cluster_labels == i]
        ith_cluster_silhouette_values.sort()
        size_cluster_i = ith_cluster_silhouette_values.shape[0]
        y_upper = y_lower + size_cluster_i
        color = cm.nipy_spectral(float(i) / n_clusters)
        ax1.fill_betweenx(np.arange(y_lower, y_upper),
                          0, ith_cluster_silhouette_values,
                          facecolor=color, edgecolor=color,       alpha=0.7)
        # Label the silhouette plots with their cluster numbers at the middle
        ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
        # Compute the new y_lower for next plot
        y_lower = y_upper + 10  # 10 for the 0 samples
    ax1.set_title("The silhouette plot for the various clusters.")
    ax1.set_xlabel("The silhouette coefficient values")
    ax1.set_ylabel("Cluster label")
    # The vertical line for average silhouette score of all the values
    ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
    ax1.set_yticks([])  # Clear the yaxis labels / ticks
    ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
    # 2nd Plot showing the actual clusters formed
    colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
    ax2.scatter(winesMmsScaler[:, 0], winesMmsScaler[:, 1], marker='.', s=30, lw=0, alpha=0.7,
                c=colors, edgecolor='k')
    # Labeling the clusters
    centers = clusterer.cluster_centers_
    # Draw white circles at cluster centers
    ax2.scatter(centers[:, 0], centers[:, 1], marker='o',
                c="white", alpha=1, s=200, edgecolor='k')
    for i, c in enumerate(centers):
        ax2.scatter(c[0], c[1], marker='$%d$' % i, alpha=1,
                    s=50, edgecolor='k')
    ax2.set_title("The visualization of the clustered data.")
    ax2.set_xlabel("Feature space for the 1st feature")
    ax2.set_ylabel("Feature space for the 2nd feature")
    plt.suptitle(("Silhouette analysis for KMeans clustering on sample data "
                  "with n_clusters = %d" % n_clusters),
                 fontsize=14, fontweight='bold')
plt.show()
Para n_clusters = 2 O score_silhouette médio é : 0.20943792
Para n_clusters = 3 O score_silhouette médio é : 0.17351092
Para n_clusters = 4 O score_silhouette médio é : 0.16409959
Para n_clusters = 5 O score_silhouette médio é : 0.18085071
Para n_clusters = 6 O score_silhouette médio é : 0.17782065
Para n_clusters = 7 O score_silhouette médio é : 0.17454065
Para n_clusters = 8 O score_silhouette médio é : 0.14196177
Para n_clusters = 9 O score_silhouette médio é : 0.1446917
Para n_clusters = 10 O score_silhouette médio é : 0.1476792
In [164]:
wines
Out[164]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5
1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8 5
2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8 5
3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8 6
4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5
... ... ... ... ... ... ... ... ... ... ... ... ...
1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5 5
1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2 6
1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0 6
1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2 5
1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6

1599 rows × 12 columns

Quantidade interessante de cluster é de 6 a 7 cluster para esta dataset

In [ ]:
 

Regressão Linear

In [42]:
#X = wineDf.drop(['quality','qualite evaluate'],axis=1)
X = wineDf.iloc[:,0:11]
y = wineDf['quality']
In [43]:
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test= train_test_split(X,y,test_size=0.3,random_state=22)
In [44]:
from sklearn.linear_model import LinearRegression
In [45]:
# Fit the model
lm = LinearRegression()
lm.fit(X_train,y_train)
Out[45]:
LinearRegression()
In [46]:
lm.coef_
Out[46]:
array([-2.48144990e-03, -1.30082064e+00, -1.85999720e-01,  9.76855022e-03,
       -2.02076816e+00,  1.28235434e-03, -3.11356838e-03,  2.60130461e+00,
       -4.57917628e-01,  9.64024381e-01,  2.80573686e-01])
In [47]:
lm.intercept_
Out[47]:
2.043552091491116

Fazendo predição

In [49]:
prediction = lm.predict(X_test)
In [51]:
sns.distplot((y_test-prediction),bins=30)
plt.title('Treino vs Predicao')
Out[51]:
Text(0.5, 1.0, 'Treino vs Predicao')

Avaliando a perfomance do modelo

Mean Absolute Error (MAE) : é a média do valor absoluto dos erros.

Mean Squared Error (MSE) : é a média do erro dos quadrados

Root Mean Squared Error (RMSE) Raiz quadrada do erro dos quadrados

In [54]:
from sklearn import metrics

print('MAE:', metrics.mean_absolute_error(y_test, pred))
print('MSE:', metrics.mean_squared_error(y_test, pred))
print('RMSE:', np.sqrt(metrics.mean_squared_error(y_test, pred)))
print('R2:', lm.score(X_train,y_train))
MAE: 0.4978386977161957
MSE: 0.3895266298369767
RMSE: 0.6241206853141279
R2: 0.3670943784891273
In [ ]: